function [s] = array2struct(A, indexMap, nonExistEleVal, keepAllNaNField)
%ARRAY2STRUCT 将二维数组转换至结构体
%
% Input Arguments:
% A: 二维数组
% indexMap: 各域为数组的结构体，各域的各元素分别表示该元素在A中对应的列数，NaN表示不存在，负数表示取负值
% nonExistEleVal: 标量或结构体，当为结构体时，各域的名称与尺寸与indexMap相同，分别表示对应的域元素在A中不存在时的默认值，默认为NaN
% keepAllNaNField: 逻辑量，是否对indexMap中元素全为NaN的域赋默认值，默认为false
%
% Output Arguments:
% s: 各域为数组的结构体，含有indexMap中元素非全为NaN的域，各域的维数比indexMap相应域的维数大1（不计indexMap域中尺寸为1的最后一维），该域的元素沿最后一维与indexMap中对应元素指定的A的列相同

if nargin < 3
    nonExistEleVal = NaN;
end

if nargin < 4
    keepAllNaNField = false;
end

fullFieldNames = fieldnames(indexMap);
fullFieldBaseNumsOfEle = zeros(1, length(fullFieldNames));
for i=1:length(fullFieldNames)
    fullFieldBaseNumsOfEle(1, i) = numel(indexMap.(fullFieldNames{i}));
end
s = struct;
lastDimSize = size(A, 1);
for i=1:length(fullFieldNames)
    for j=1:fullFieldBaseNumsOfEle(1, i)
        arrColIdx = indexMap.(fullFieldNames{i})(j); % 使用线性索引
        if ~isnan(arrColIdx) || keepAllNaNField
            if ~isfield(s, fullFieldNames{i})
                % 如s中尚不存在该域则以默认值创建该域
                sizeVec = size(indexMap.(fullFieldNames{i}));
                if sizeVec(end) == 1
                    sizeVec = sizeVec(1:end-1);
                end
                if isstruct(nonExistEleVal)
                    s.(fullFieldNames{i}) = repmat(nonExistEleVal.(fullFieldNames{i}), [ones(1, length(sizeVec)) lastDimSize]);
                else
                    s.(fullFieldNames{i}) = nonExistEleVal * ones([sizeVec lastDimSize]);
                end
            end
        end
        if ~isnan(arrColIdx)
            linearIdx = j:fullFieldBaseNumsOfEle(1, i):(j+(lastDimSize-1)*fullFieldBaseNumsOfEle(1, i)); % NOTE: 与MATLAB使用的以列为主的索引方法相关
            s.(fullFieldNames{i})(linearIdx) = sign(arrColIdx) * A(:, abs(arrColIdx)); % 使用线性索引
        end
    end
end
end